package com.asa.utils;

import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

import com.asa.HanShu;

public class Calculate {
	
	
	/**
	 * 求解函数的零点,可以稳定的求出解范围在绝对值500万以内的二元一次方程的解
	 * 对于更多零点的解由于无法获取好的初值，无法求太多解，不是计算不出来，而是不稳定，但两个解还是没有问题的
	 * 如果是想要通用的求出所有的解的，基本上是和无限在做敌对
	 * @param js	解的个数
	 * @param hanShu	函数方程
	 * @return	零点结果的组
	 */
	public static double[] hangshujie(int js,HanShu hanShu){
		double[] x = new double[js]; 
		double x0 = 0;
		for (int i = 0; i < 2; i++) {
			x[i] = MathUtils.niudun((i-0.5)*10000000, hanShu);
			//System.out.println((i-0.5)*10000000);
		}
		if (js>2) {
			for (int i = 2; i < x.length; i++) {
				x[i] = MathUtils.niudun((x[i-1]-x[i-2])/2+x[i-2], hanShu);
			}	
		}
		for (int i = 0; i < x.length; i++) {//精确
			NumberFormat nf = NumberFormat.getInstance();
	        nf.setRoundingMode(RoundingMode.HALF_UP);//设置四舍五入
	        nf.setMinimumFractionDigits(3);//设置最小保留几位小数
	        nf.setMaximumFractionDigits(3);//设置最大保留几位小数
	        //System.out.println(nf.format(x[i]));
			x[i] = Double.parseDouble(nf.format(x[i]));
		}
		
		return x;
	}
	
	
	
	/**
	 * 求解线性方程组，数据的格式有要求比较死板，需要在下一层来做
	 * 
	  * @param a n元n次矩阵
	 * @param b	n元矩阵
	 * @return 解集
	 */
	public static double[] fangchengzudejie(double a[][],double b[]){
	
		double[] x = MathUtils.duoyuanyici(a, b);
		for (int i = 0; i < x.length; i++) {//精确
			NumberFormat nf = NumberFormat.getInstance();
	        nf.setRoundingMode(RoundingMode.HALF_UP);//设置四舍五入
	        nf.setMinimumFractionDigits(3);//设置最小保留几位小数
	       // //System.out.println(nf.format(x[i]));
//			x[i] = Double.parseDouble(nf.format(x[i]));
		}
		return x;
		
	}
	
	/**
	 * 根据点求出行数的值
	 * @param x	x对应y的集
	 * @param y	y对应x的集
	 * @return	得出函数的解，形式是通用的，插值的
	 * p(x)=1+2(x-5)+3(x-5)(x+7)+4(x-5)(x+7)(x+6) 
	 */
	public static String hanshunihe1(double x[],double y[]){
		double[] hangshuhuoqu = MathUtils.hangshuhuoqu(x, y);
		String s = "";
		String s2 = "";
		for (int i = 0; i < hangshuhuoqu.length; i++) {
			if (i!=0) {	
			if (x[i-1]<0) {
				s2 = s2+"(x"+x[i-1]+")";
			}else{
				if (x[i]!=0) {
					s2 = s2+"(x+"+x[i-1]+")";
				}else{
					s2 = s2+"x";
				}
			}
			}
			if (i!=0) {
				s = s+"+"+hangshuhuoqu[i]+s2;
			}else{
				s = s+hangshuhuoqu[i]+s2;
			}
		}
		return s;
	}
	/**
	 * 根据点求出行数的值
	 * @param x	x对应y的集
	 * @param y	y对应x的集
	 * @return	函数的解方程，因式分解都做好了
	 */
	public static String hanshunihe2(double x[],double y[]){
		
		double[] hangshuhuoqu = MathUtils.hangshuhuoqu(x, y);
		double[][] d = new double[x.length][x.length]; 
		double[] a = new double[x.length];
		d[0][0] = 1;
		for (int i = 1; i < d.length; i++) {
			d[i][0] = 1;
			d[i][i] = d[i-1][i-1]*x[i-1];
			for (int j = 1; j < i; j++) {
				if (i==3) {
					//System.out.println("........."+d[i-1][j]+"======="+x[i-1]);
				}
				d[i][j] = d[i-1][j] + x[i-1]*d[i-1][j-1] ;
			}
		}
		for (int i = 0; i < d.length; i++) {
			for (int j = 0; j < d[i].length; j++) {
				System.out.print(d[i][j]+"   ");
			}
			//System.out.println();
		}
		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < a.length-i; j++) {
				a[i] += d[i+j][j]*hangshuhuoqu[i+j];
			}
		}
		//System.out.println("========================");
		String ss = "";
		for (int i = 0; i < a.length; i++) {
			//System.out.println(a[i]);
			if (i==0) {
				ss = ss+a[i];
			}else{
				if (a[i]>0) {
					ss = ss+"+"+a[i]+"x^"+i;
				}else{
					ss = ss+a[i]+"x^"+i;
				}
			}
		}
		return ss;
	}
	
	/**
	 * 
	 * 求函数积分
	 * 这个方式简单，但比较粗糙
	 * @param a	积分的初始位置
	 * @param b	积分的结束位置
	 * @param hanShu	你期望求解的函数
	 * @return 	积分解值
	 */
	public static double hanshujifen(double a,double b, HanShu hanShu){
		double longBeiGe1 = 0;
		double longBeiGe2 = 0;
		if (a<0&&b>0) {
			longBeiGe1 = Math.abs(MathUtils.longBeiGe(a, 0, hanShu));
			longBeiGe2 = Math.abs(MathUtils.longBeiGe(0, b, hanShu));
		}else{
			longBeiGe2 = MathUtils.longBeiGe(a, b, hanShu);
		}
		
		
		double longBeiGe = longBeiGe1+longBeiGe2;
		NumberFormat nf = NumberFormat.getInstance();
        nf.setRoundingMode(RoundingMode.HALF_UP);//设置四舍五入
        nf.setMinimumFractionDigits(6);//设置最小保留几位小数
       
		
		return Double.parseDouble(nf.format(longBeiGe));
		
	}
	/**
	 * 简单积分
	 * @param a
	 * @param b
	 * @param hanShu
	 * @return
	 */
	public static double hanshujifen2(double a,double b, HanShu hanShu){
		double buchang = 0.0001;
		double d = 0;
		while(true){
			double h1 = hanShu.hanshu(a);
			a+=buchang;
			double h2 = hanShu.hanshu(a);
			d+=(h1+h2)*buchang/2;
			
			if (a>=b) {
				break;
			}
		}

		return d;
		
	}
	
	
	
	/**
	 * 常微分方程数值解法,常微分方程要在大学接触，而且一般结构精度要求比较高，就直接返回结果了
	 * @param t	t的初始值
	 * @param x	对应t的初始值得x值
	 * @param tt	要求的t值对应x
	 * @param hanShu	偏微分方程值
	 * @return	要求的点的x的值
	 */
	public static double hanshuchangweifen(double t,double x,double tt,HanShu hanShu){
		
		return MathUtils.siJieLongGe(t, x, tt, hanShu);
	}
	
	
	/**
	 * 拟合函数，这种比较高级，最后拟合出来的函数也比较复杂
	 * 这个算法一般在实际统计中使用，而上面的函数拟合更多用于计算确定的数学函数
	 * @param x	拟合x值
	 * @param y	拟合y值
	 * @return	返回最终结果，这里将最终函数拼接好了
	 * 
	 * 插值法所生成的函数，必定会经过拟合点，而这种方式，他会最大限度的使函数达到平衡
	 * 
	 */
	public static String nihe(double[] x ,double[] y) {
		
		double[] nihe = Norm.nihe(x, y);
		String all="y="+nihe[0]+"lnx";
		if ( nihe[1]<0) {
			all = all+nihe[1]+"cosx";
		}else{
			all = all+"+"+nihe[1]+"cosx";
		}
		if ( nihe[2]<0) {
			all = all+nihe[2]+"e^x";
		}else{
			all = all+"+"+nihe[2]+"e^x";
		}
		
//		+nihe[1]+"cosx"+nihe[2]+"e^x"
		return all;
	}
	
	
	/**
	 *	计算阶乘 
	 *	1*2*3...
	 *
	 */
	public static int jiecheng(int k){
		int all = 1;
		for (int i = 1; i <= k; i++) {
			all = all*i;
		}
		return all;
	}
	
	
	/**
	 *	计算反阶乘 
	 *	n和m	
	 *	n * n-1 * n-2 ... n-m
	 *
	 */
	public static int ni_jiecheng(int n,int m){
		int all = 1;
		for (int i = 1; i < m; i++) {
			all = (n-i)*all;
		}
		return all;
	}
	
	
	
	
	
	
	/**
	 * 排列组合中的组合C
	 * 的计算
	 */
	public static double zuhe(double n,double r){
		double a = jiecheng((int)n);
		double b = jiecheng((int)r);
		double c = jiecheng((int)(n-r));
		return a/(b*c);
	}
	
	/**
	 * 	从n个中选出m个，有多少个组合，列出来
	 * @param n
	 * @param m
	 * @return
	 */
	public static List<int[]> zuhe_list(int n,int m) {
		// TODO Auto-generated method stub
		int start = 0;
		int max = n-start;
		return zuhe_list(n, m, start,max);
	}
	
	
	
	public static List<int[]> zuhe_list(int n,int m,int start,int max) {
		
//		max = n - start;
		
//		if ((n-start)<=m) {
		if(m==1) {//n个里面选1个，是跳出递归的条件
//			System.out.println("(n-start)<=m");
			List<int[]> result = new ArrayList<int[]>();
			for (int i = start; i < max; i++) {
				int[] asa = new int[m];
				
				asa[m-1] = i;
				result.add(asa);

			}
			return result;
		}
		List<int[]> result = new ArrayList<int[]>();
		
		
		if ((max-m)==start) {//n个里面选n个，是跳出递归的条件
			int[] e = new int[m];
			for (int j = 0; j < e.length; j++) {
				e[j] = start +j;
			}
			result.add(e);
			return result;
		}
		
		
		for (int i = start; i < n; i++) {
			List<int[]> zuhe_list = new ArrayList<int[]>();
			

			
			zuhe_list = zuhe_list(n-1, m-1, i+1,max);
			
//			System.out.println(zuhe_list.size()+"size");
			
			for (int j = 0; j < zuhe_list.size(); j++) {
				int[] ks = zuhe_list.get(j);
				
				int[] asa = new int[ks.length+1];
				asa[0] = i;
				for (int k = 1; k < asa.length; k++) {
					asa[k] = ks[k-1];
				}
				result.add(asa);
				
				
			}
			

		}
		
		return result;
		
		
	}
	
	
	
	
	public static void main(String[] args) {
		
		List<int[]> zuhe_list = zuhe_list(4, 2);
		
		
		for (int i = 0; i < zuhe_list.size(); i++) {
			int[] js = zuhe_list.get(i);
			for (int j = 0; j < js.length; j++) {
				System.out.print(js[j]+"        ");
			}
			System.out.println();
		}
		
		
		
	}
	
	
	
	
	
	/***************************概率拟合求值*********************************************/
	
	
	
	
}
